﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Sl.Log;
using ChholCmdPort;
using Microsoft.VisualBasic.Devices;
using Sl.Duplex;
using Sl.Forms;
using System.Xml.Xsl;
using System.Reflection;

namespace ChholConfig {
	public partial class ChholCommunicator : Form {
		//#255f64
		Logger log;
		Cc9d.Cc9dCodec main_Codec;
		Cc9d.Cc9dCodec toHex_Codec;//这是用来将发送数据转换为发送HEX并显示的解码器
		RecvFanOut Recv_fanout;
		string port_name;
		string Port_name {
			get => port_name;
			set {
				if (port_name != value) {
					port_name = value;
					if ((port_name != null) && (port_name.Length > 0)) {
						PortOnOffBTN.Enabled = true;
					} else {
						PortOnOffBTN.Enabled = false;
					}
				}
			}
		}
		readonly public string cmd_desc = ChholCode.cmd_desc;
		Audio main_audio = new Audio();

		void addTool(Type type) {//这个类型必须是PortUserForm
								 //检查一下是不是
			if (type.IsSubclassOf(typeof(PortUserForm)) == false) {
				return;
			}

			var item = new ToolStripMenuItem();
			//使用反射，获取ToolName，ToolIcon，ToolDesc

			var toolNameField = type.GetField("ToolName", BindingFlags.Public | BindingFlags.Static);
			if (toolNameField != null && toolNameField.FieldType == typeof(string)) {
				string toolName = (string)toolNameField.GetValue(null);
				item.Text = toolName;
			}

			var toolIconField = type.GetField("ToolIcon", BindingFlags.Public | BindingFlags.Static);
			if (toolIconField != null && toolIconField.FieldType == typeof(Bitmap)) {
				Bitmap toolIcon = (Bitmap)toolIconField.GetValue(null);
				item.Image = toolIcon;
			}

			var toolDescField = type.GetField("ToolDesc", BindingFlags.Public | BindingFlags.Static);
			if (toolDescField != null && toolDescField.FieldType == typeof(string)) {
				string toolDesc = (string)toolDescField.GetValue(null);
				item.ToolTipText = toolDesc;
			}
			PortControlDDB.DropDownItems.Add(item);
			item.Click += (s, e) => {
				var form = (PortUserForm)Activator.CreateInstance(type, Recv_fanout, this);

				addPortBtn(form);
			};

		}




		public ChholCommunicator() {
			InitializeComponent();
			this.Text = "斥候命令通信器" + Program.version;

			rsRTB.Click += rsRTB_Click;
			sendBTN.Click += sendBTN_Click;
			CmdLock.Click += switchLock;
			AddrLAB.Click += AddrLAB_Click;
			PortSelectCB.SelectedIndexChanged += PortSelectCB_SelectedIndexChanged;
			PortOnOffBTN.Click += PortOnOffBTN_Click;
			ScanBTN.Click += searchPort_Click;

			测试脚本执行器ToolStripMenuItem.Click += 启动lua脚本ToolStripMenuItem_Click;
			用户串口通信器ToolStripMenuItem.Click += 组网节点串口通信器端口16ToolStripMenuItem_Click;
			网络参数配置器ToolStripMenuItem.Click += 网络参数配置器ToolStripMenuItem_Click;

			addTool(typeof(MutNodeControl));



			log = new TimerLogger(new LoggerToRTB(rsRTB) { word_color_pair = sr_color_pair });
			Recv_fanout = new RecvFanOut();
			Recv_fanout.defaultRecvPkg = this.recvPkg;
			helpBTN.Text = cmd_desc;
			toHex_Codec = new Cc9d.Cc9dCodec(to_hex_dp) {
				Log = Program.Log,
			};
		}
		private void reportMessafg(string msg) {
			log.LogLine(msg);
		}




		public void openFixPort(string port) {
			Port_name = port;
			startPort();
			PortSelectCB.Text = $"{port}固定端口";
			PortSelectCB.Enabled = false;
			ScanBTN.Enabled = false;
		}


		private void searchPort_Click(object sender, EventArgs e) {
			searchPort();
		}
		public void searchPort() {
			SerialPortSelecter serial_port_selecter;
			closePort();
			PortSelectCB.Items.Clear();
			serial_port_selecter = new SerialPortSelecter();
			if (serial_port_selecter.Ports.Length == 0) {
				reportMessafg($"【报告】没有找到任何端口。");
				return;
			} else {
				int avaliable_port = serial_port_selecter.Avaliable_port_num;
				int totle_port = serial_port_selecter.Ports.Length;
				foreach (var cpd in serial_port_selecter.Ports) {
					PortSelectCB.Items.Add(cpd);
				}
				if (avaliable_port != 0) {
					PortSelectCB.SelectedIndex = 0;
					reportMessafg($"【报告】搜索完成，找到{avaliable_port}/{totle_port}个端口，打开了{PortSelectCB.Text}。");
				} else {
					reportMessafg($"【报告】搜索完成，找到{avaliable_port}/{totle_port}个端口，没有打开任何端口。");
				}
			}
		}

		private void PortSelectCB_SelectedIndexChanged(object sender, EventArgs e) {
			Port_name = (PortSelectCB.SelectedItem as ComPortDesc).id;
			startPort();
		}
		IDuplex main_sp;
		ToHexDp to_hex_dp = new ToHexDp();
		void startPort() {
			closePort();
			string warning;
			main_sp = new SerialPortDp(Port_name, out warning);
			main_sp.ePortStatusChange += Main_sp_ePortStatusChange;
			if (warning != "") {
				reportMessafg($"【报告】打开{main_sp.Name}失败，原因：{warning}。");
				main_sp = null;
				return;
			}
			main_sp.openPort();
			if (main_sp.IsRunning == false) {
				reportMessafg($"【报告】打开{main_sp.Name}失败。");
				return;
			}
			main_Codec = new Cc9d.Cc9dCodec(main_sp) {
				Log = Program.Log,
				dRecvEcmd = b => this.log.LogLine($"【转义】{b:X2}。"),

			};
			Recv_fanout.dSendPkg = p => main_Codec.send(p.cc9d_pkg);
			main_Codec.dRecvPkg = bp => Recv_fanout.recvPkg(new Pkg(bp));
			cmdCRTB.inputCmd = (cmd) => {
				ChholCmdPort.Pkg p;
				bool rev = codeToPkg(cmd, out p);
				if (rev) {
					sendPkg(p);
				}
				return rev;
			};
			refreshPortStatus();
		}
		void closePort() {

			cmdCRTB.inputCmd = null;
			if (main_sp != null) {
				reportMessafg($"【报告】关闭了{main_sp.Name}。");
				main_sp.ePortStatusChange -= Main_sp_ePortStatusChange;
				main_sp.closePort();
				main_sp = null;
				Recv_fanout.dSendPkg = null;
				main_Codec.dRecvPkg = null;
				main_Codec.Dispose();

			}
			refreshPortStatus();
		}

		private void Main_sp_ePortStatusChange(IDuplex obj) {
			if (obj.IsRunning) {
				reportMessafg($"【报告】成功打开了{main_sp.Name}。");

			} else {
				closePort();
			}
		}

		bool is_port_open {
			get {
				if (main_sp == null) {
					return false;
				} else {
					return main_sp.IsRunning;
				}
			}
		}

		private void PortOnOffBTN_Click(object sender, EventArgs e) {
			if (is_port_open) {
				closePort();
			} else {
				startPort();
			}
		}

		void refreshPortStatus() {
			if (is_port_open) {
				this.PortOnOffBTN.Image = global::ChholConfig.Properties.Resources.connected_30px;
				PortOnOffBTN.Text = "将端口关闭";
				sendBTN.Enabled = true;
				updataAddr();
			} else {
				this.PortOnOffBTN.Image = global::ChholConfig.Properties.Resources.disconnected_30px;
				PortOnOffBTN.Text = "将端口打开";
				sendBTN.Enabled = false;
			}
		}
		void updataAddr() {
			Task.Run(() => {
				var port = Recv_fanout.createPortUser();
				Console.WriteLine("开始追踪端口31");
				port.Run(31);
				port.dRecvPkg = pkg => {
					ushort addr = (ushort)((pkg[2] << 8) + pkg[1]);
					ushort pan = (ushort)((pkg[4] << 8) + pkg[3]);
					updateAp(addr, pan);
					port.stop();
					Console.WriteLine("停止追踪端口31");
					return true;
				};
				Task.Delay(300).Wait();
				//构造包
				Pkg p = new Pkg();
				p.From_port = 31;
				p.To_port = 103;
				p.Remote_addr = 0xfff0;
				p.Data_len = 1;
				p[0] = (byte)'R';
				port.sendPkg(p);
				Task.Run(() => {
					Task.Delay(300).Wait();
					if (port.Is_running) {
						port.stop();
						Console.WriteLine("没有收到地址报告，停止追踪端口31");
					}
				});
			});
		}



		static public (string word, Color color)[] sr_color_pair = {
			("收到", Color.DarkGreen),
			("发出", Color.DarkRed),
			("错误", Color.DarkOrange),
			("编码", Color.Navy),
			("报告", Color.Black),
		};

		private void recvPkg(Pkg p) {
			if (this.InvokeRequired) {
				this.BeginInvoke(new Action<Pkg>(recvPkg), p);
				return;
			}
			log.LogLine($"【收到】{p}");

		}
		//将字符串的命令转换为包
		private bool codeToPkg(string code, out Pkg p) {
			string report;
			byte from_port;
			if (false == Byte.TryParse(fromPortTB.Text, out from_port)) {
				p = null;
				report = $"源端口解析错误({fromPortTB.Text})";
			} else {
				report = ChholCode.codeToPkg(code, from_port, out p);
			}
			if (report == null) {
				return true;
			} else {
				main_audio.PlaySystemSound(System.Media.SystemSounds.Beep);
				badCmdTT.Show(report, cmdCRTB, 10000);
				return false;
			}
		}

		void sendPkg(Pkg p) {
			try {
				main_Codec.send(p.cc9d_pkg);
				log.LogLine($"【发出】{p}");
			} catch (InvalidOperationException ex) {
				main_audio.PlaySystemSound(System.Media.SystemSounds.Beep);
				badCmdTT.Show("串口被意外关闭了", cmdCRTB, 10000);
				closePort();
			}
		}
		void toHexPkg(Pkg p) {
			toHex_Codec.send(p.cc9d_pkg);
			log.LogLine($"【编码】{p}得到 [ {to_hex_dp.getAllString()}]");
		}

		private void rsRTB_Click(object sender, EventArgs e) {
			if (rsRTB.Text.Length < 10) {
				return;
			}
			int select_point = rsRTB.SelectionStart;
			//圈定搜索范围
			int search_bgn = rsRTB.SelectionStart - 10;
			int search_end = rsRTB.SelectionStart + 10;
			if (search_bgn < 0) {
				search_bgn = 0;
			}
			if (search_end >= rsRTB.Text.Length) {
				search_end = rsRTB.Text.Length - 1;
			}
			int arror = rsRTB.Text.IndexOf("->", search_bgn, search_end - search_bgn);
			search_bgn = arror - 9;
			search_end = search_bgn + 20;
			if (search_bgn < 0) {
				search_bgn = 0;
			}
			if (search_end >= rsRTB.Text.Length) {
				search_end = rsRTB.Text.Length - 1;
			}
			string line = rsRTB.Text.Substring(search_bgn, search_end - search_bgn);
			arror = line.IndexOf("->");
			int dot = line.IndexOf(".");
			if (arror == -1) { return; }
			if (dot == -1) { return; }
			if (dot < arror) {
				cmdCRTB.Clear();
				cmdCRTB.Text = line.Substring(dot - 4, arror - (dot - 4)) + ": ";
			} else {
				cmdCRTB.Clear();
				cmdCRTB.Text = line.Substring(arror + 2, line.IndexOf(' ', arror + 2) - (arror + 2)) + ": ";
			}
		}


		private void switchLock(object sender, EventArgs e) {
			if (cmdCRTB.Is_Cmd_Send_clean) {
				cmdCRTB.Is_Cmd_Send_clean = false;
				this.CmdLock.Image = global::ChholConfig.Properties.Resources.lock_26px;
			} else {
				cmdCRTB.Is_Cmd_Send_clean = true;
				this.CmdLock.Image = global::ChholConfig.Properties.Resources.unlock_26px;

			}
		}
		private void sendBTN_Click(object sender, EventArgs e) {
			cmdCRTB.send();
		}

		void addPortBtn(IPortUserUI puui) {
			ToolStripButton new_portBTN = new ToolStripButton();
			new_portBTN.Tag = puui;
			new_portBTN.Image = puui.Bmp;
			new_portBTN.Text = puui.getPortName();
			puui.ePortNameChanged += (s, _e) => new_portBTN.Text = puui.getPortName();
			new_portBTN.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
			new_portBTN.Click += New_portBTN_Click;
			puui.eClosed += (s, _e) => {
				topTS.Items.Remove(new_portBTN);
				new_portBTN.Click -= New_portBTN_Click;
				new_portBTN.Dispose();
			};
			topTS.Items.Add(new_portBTN);
			puui.showForm();
		}


		private void 启动lua脚本ToolStripMenuItem_Click(object sender, EventArgs e) {
			addPortBtn(new LuaForm(Recv_fanout, this));
		}

		private void 组网节点串口通信器端口16ToolStripMenuItem_Click(object sender, EventArgs e) {
			addPortBtn(new UserSerial.UsrUartTopic(Recv_fanout, this));
		}
		private void New_portBTN_Click(object s_, EventArgs e_) {
			IPortUserUI cp_ = (s_ as ToolStripButton).Tag as IPortUserUI;
			cp_.showForm();
		}


		private void 网络参数配置器ToolStripMenuItem_Click(object sender, EventArgs e) {
			addPortBtn(new Configer.Configer(Recv_fanout, this));
		}

		private void AddrLAB_Click(object sender, EventArgs e) {
			updataAddr();
		}


		private void updateAp(ushort addr, ushort pan) {
			if (this.InvokeRequired) {
				this.Invoke(new Action(DO));
			} else {
				DO();
			}
			void DO() {
				this.AddrLAB.Text = $"{addr:X4}-{pan:X4}";
			}

		}

		private void ToHexBTN_Click(object sender, EventArgs e) {
			ChholCmdPort.Pkg p;
			bool rev = codeToPkg(cmdCRTB.Text, out p);
			if (rev) {
				toHexPkg(p);
			}
			return;
		}

		private void recycleBTN_Click(object sender, EventArgs e) {

		}

		private void ClearBTN_Click(object sender, EventArgs e) {
			if (rsRTB.Text.Length > 1600) {
				var index = rsRTB.Text.IndexOf('\n', rsRTB.TextLength - 1500);
				//rsRTB删除index前面的内容
				rsRTB.ReadOnly = false;
				rsRTB.Select(0, index);
				rsRTB.SelectedText = "";
				rsRTB.ReadOnly = true;
				rsRTB.Select(rsRTB.TextLength, 0);
				rsRTB.ScrollToCaret();
			} else {
				rsRTB.Clear();
			}
		}

		private void rsRTB_SelectionChanged(object sender, EventArgs e) {
			if (rsRTB.SelectedText.Length == 0) {
				HaDecLab.Text = "";
				HaSrtLab.Text = "";
				return;
			}
			//获取选中的文本
			string select_text = rsRTB.SelectedText;
			//找到最后一个冒号，去掉冒号和前面的部分
			int last_colon = select_text.LastIndexOf(':');
			if (last_colon != -1) {
				select_text = select_text.Substring(last_colon + 1);
			}
			//找到第一个回车，去掉回车和后面的部分
			int first_enter = select_text.IndexOf('\n');
			if (first_enter != -1) {
				select_text = select_text.Substring(0, first_enter);
			}
			select_text = select_text.Trim();
			string[] texts = select_text.Split(' ');
			byte[] bs = new byte[texts.Length];
			for (int i = 0; i < texts.Length; i++) {
				if (false == Byte.TryParse(texts[i], System.Globalization.NumberStyles.HexNumber, null, out bs[i])) {
					HaDecLab.Text = "无法解析";
					HaSrtLab.Text = "";
					return;
				}
			}
			if (bs.Length == 1) {
				HaDecLab.Text = bs[0].ToString();
			} else if (bs.Length == 2) {
				HaDecLab.Text = ((bs[1] << 8) + bs[0]).ToString();
			} else if (bs.Length == 4) {
				HaDecLab.Text = ((bs[3] << 24) + (bs[2] << 16) + (bs[1] << 8) + bs[0]).ToString();
			} else {
				HaDecLab.Text = "";
			}
			HaSrtLab.Text = Encoding.ASCII.GetString(bs);


		}

		private void wakeUpBtn_Click(object sender, EventArgs e) {
			this.main_Codec.sendSeparator();

		}
	}
}
